﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.SharePoint.Administration;
using System.Collections.ObjectModel;
using System.Threading;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.IO;
using System.Xml;

namespace bulkDeployment
{
    public partial class frm1 : Form
    {
        public frm1()
        {
            InitializeComponent();
            LoadSettings();
            this.btnDeploy.Enabled = false;
            this.btnChangeVPath.Enabled = false;
            this.rbwsp.Checked = true;
            getFarmSolutions();
        }
        private string url = null;
        private string searchtext = "*.wsp";

        private void LoadSettings()
        {
            getZones();
            this.txtmaifest.Text = Properties.Settings.Default.ManifestName;
            this.cbManifest.Checked = Properties.Settings.Default.WSPName;
            if (Properties.Settings.Default.SearchFor == true)
            {
                this.rbwsp.Checked = Properties.Settings.Default.SearchFor;
            }
            else
            {
                this.rbcab.Checked = Properties.Settings.Default.SearchFor;
            }
            this.txtDefaultFolder.Text = Properties.Settings.Default.location;
            this.cbburlzone.SelectedIndex = Properties.Settings.Default.zone;
            this.cbbZone.SelectedIndex = Properties.Settings.Default.zone;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            getWebApps(false,false);

            lblWarning.Text = "WARNING" + Environment.NewLine +
                "This will change your virtual directory for your web application." + Environment.NewLine +
                "If you manually changed your virtual directory and get somthing similar to the following error: " + Environment.NewLine + Environment.NewLine +
                "'Error: The web.config is missing from this IIS Web Site: c:\\inetpub\\wwwroot\\web.config' " + Environment.NewLine + Environment.NewLine +
                "but you know it exists at 'C:\\Inetpub\\wwwroot\\wss\\VirtualDirectories\\80'"+ Environment.NewLine+
                "Using this tool you can change the directory to point to the new location." + Environment.NewLine + Environment.NewLine +
                "1) You need to first enter the url for the given web application that you want to change." + Environment.NewLine +
                "2) You now need to click on the button to select the new path where the web application currently exists" + Environment.NewLine + Environment.NewLine +
                "Only do this if you changed the virtual directory location manually and need to update sharepoint";
        }

        private void getWebApps(bool getURL, bool cb1)
        {
            SPServiceCollection services = SPFarm.Local.Services;

            foreach (SPService curService in services)
            {
                if (curService is SPWebService)
                {
                    SPWebService webService = (SPWebService)curService;

                    foreach (SPWebApplication webApp in webService.WebApplications)
                    {
                        if (getURL == false)
                        {
                            if (webApp.Name != "")
                            {
                                this.cbbwebApps1.Items.Add(webApp.Name);
                                this.cbbwebApps2.Items.Add(webApp.Name);
                            }
                        }
                        else
                        {
                            if (cb1 == true)
                            {
                                if (webApp.Name == this.cbbwebApps1.SelectedItem.ToString())
                                {
                                    url = webApp.GetResponseUri(SPUrlZone.Default).AbsoluteUri;
                                }
                            }
                            else
                            {
                                if (webApp.Name == this.cbbwebApps2.SelectedItem.ToString())
                                {
                                    url = webApp.GetResponseUri(SPUrlZone.Default).AbsoluteUri;
                                }
                            }
                        }
                    }
                }
            }
        }

        private void btnDeploy_Click(object sender, EventArgs e)
        {
            this.btnDeploy.Enabled = false;

            if (txtLogging.Text != "")
            {
                txtLogging.Clear();
            }

            executeSolution(true);
        }

        private void executeSolution(bool add)
        {
            try
            {                        
                Collection<SPWebApplication> webapps = new Collection<SPWebApplication>();
                SPWebApplication webapp = SPWebApplication.Lookup(new Uri(url));
                webapps.Add(webapp);

                SPSolutionCollection spSC = SPFarm.Local.Solutions;
                foreach (SPSolution spSolution in spSC)
                {

                    if (spSolution.ContainsWebApplicationResource)
                    {
                        if (add == true)
                        {
                            //deploy
                            spSolution.Deploy(DateTime.Now, true, webapps, true);
                            //logging
                            txtLogging.Text += spSolution.DisplayName + " to " + url + Environment.NewLine;
                        }
                        else
                        {
                            foreach (SPWebApplication weba in spSolution.DeployedWebApplications)
                            {
                                if (weba.Name == webapps[0].Name)
                                {
                                    //retract
                                    spSolution.Retract(DateTime.Now, webapps);
                                    //logging
                                    txtdebug.Text += spSolution.DisplayName + " removed from " + url + Environment.NewLine;
                                    break;
                                }
                            }
                            
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            this.btnDeploy.Enabled = true;
            MessageBox.Show("Done, Please give it time for all the webparts that have been deployed to deploy." + Environment.NewLine + "Depending on the ammount of webparts deployed will determin how long it will take." + Environment.NewLine + "You will notice your web app performe an iisreset for each deployed webpart");
        }

        private void btnChangeVPath_Click(object sender, EventArgs e)
        {
            updateVirtualPath();
        }

        List<SPUrlZone> listZone = new List<SPUrlZone>();
        private void getZones()
        {
            this.listZone.Add(SPUrlZone.Default);
            this.listZone.Add(SPUrlZone.Custom);
            this.listZone.Add(SPUrlZone.Extranet);
            this.listZone.Add(SPUrlZone.Internet);
            this.listZone.Add(SPUrlZone.Intranet);

            foreach (SPUrlZone z in listZone)
            {
                this.cbbZone.Items.Add(z);
                this.cbburlzone.Items.Add(z);
            }
        }

        private void updateVirtualPath()
        {
            this.btnChangeVPath.Enabled = false;
            try
            {
                using (SPSite site = new SPSite(this.txtUrl.Text))
                {
                    //get site's web application IIS Settings
                    SPIisSettings iisSettings = site.WebApplication.IisSettings[(SPUrlZone)this.cbburlzone.SelectedItem];
                    string folderPath = string.Empty;

                    using (FolderBrowserDialog fdb = new FolderBrowserDialog()) 
                    {
                        fdb.SelectedPath = @txtDefaultFolder.Text;
                        if (fdb.ShowDialog() == DialogResult.OK )
                        {
                            folderPath = fdb.SelectedPath;
                            
                            iisSettings.Path = new System.IO.DirectoryInfo(@folderPath);

                            //Call the Update method of the web application
                            site.WebApplication.Update();

                            MessageBox.Show("Your new virtual path has been changed to " + folderPath);

                            this.btnChangeVPath.Enabled = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex.Message == "Invalid URI: The format of the URI could not be determined.")
                {
                    MessageBox.Show("You must enter a valid URL with http(s)://");
                }
                else
                {
                    MessageBox.Show(ex.Message);
                }
            }

        }

        private void txtUrl_TextChanged(object sender, EventArgs e)
        {
            if (txtUrl.Text.Length != 0)
            {
                this.btnChangeVPath.Enabled = true;
            }
            else
            {
                this.btnChangeVPath.Enabled = false;
            }
        }

        private void cbbwebApps2_SelectedIndexChanged(object sender, EventArgs e)
        {
            getWebApps(true,false);
            this.btnRemoveWebApp.Enabled = true;
        }

        private void btnRemoveWebApp_Click(object sender, EventArgs e)
        {

            this.btnRemoveWebApp.Enabled = false;

            if (txtLogging.Text != "")
            {
                txtLogging.Clear();
            }

            executeSolution(false);

        }

        private void cbbwebApps1_SelectedIndexChanged(object sender, EventArgs e)
        {
            getWebApps(true,true);
            this.btnDeploy.Enabled = true;
        }

        private void getFarmSolutions()
        {
            foreach (SPSolution s in SPFarm.Local.Solutions)
            {
                solutionslist.Add(s.SolutionId);
            }
        }

        private List<Guid> solutionslist = new List<Guid>();

        private void btnAdd_Click(object sender, EventArgs e)
        {
            string folderPath = string.Empty;
            using (FolderBrowserDialog fdb = new FolderBrowserDialog())
            {
                if (fdb.ShowDialog() == DialogResult.OK)
                {
                    folderPath = fdb.SelectedPath;
                    //look in the following directory for wsp files only including subdirectories
                    string[] filePaths = Directory.GetFiles(@folderPath, searchtext, SearchOption.AllDirectories);

                    foreach (string path in filePaths)
                    {                        
                        //get path
                        string wspname = path;
                        //split path where it contains \\
                        string[] wsp = wspname.Split('\\');
                        //get the last part of the path within the array by getting the string array total ammount -1
                        wspname = wsp[wsp.GetLength(0)-1];
                        
                        //get the full path length
                        int startpathlength = path.Length;
                        //get the wsp name length
                        int removelength = wspname.Length;
                        //remove the wsp name length from the path length
                        startpathlength = startpathlength - removelength;

                        //get the wsp name and make it into a manifest name with extention of .xml (for advanced settings)
                        string manifestName = wspname;

                        if (rbwsp.Checked == true)
                        {
                            manifestName = manifestName.Replace(".wsp", ".xml");
                        }
                        else
                        {
                            manifestName = manifestName.Replace(".cab", ".xml");
                        }
                        
                        string manifestPath = path;
                        //return the path without the wsp name and extention
                        manifestPath = manifestPath.Remove(startpathlength, removelength);
                        
                        //get guid from manifest
                        Guid guid = GetSolutionIdFrommanifest(manifestPath, manifestName);

                        //check to see wsp already exists in solution store
                        if (!solutionslist.Exists(guid.Equals))
                        {
                            SPSolution mySolution = SPFarm.Local.Solutions.Add(@path);
                            //display to screen result
                            this.txtAddResult.Text += "successfully Added (" + wspname +")"+ Environment.NewLine;
                        }
                        else
                        {
                            //upgrade wsp as its already in solution store
                            this.txtAddResult.Text += "Solution file (" + wspname + ") already exists.... Upgrading......." + Environment.NewLine;
                            UpgradeSolution(path, guid);
                            this.txtAddResult.Text += "Solution file (" + wspname + ") upgraded sucessfully" + Environment.NewLine;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// reads the SolutionId from manifest.xml
        /// </summary>
        /// <param name="packageName">the full path to the solution package</param>
        /// <returns>SolutionId (GUID) contained in manifest.xml</returns>
        public Guid GetSolutionIdFrommanifest(string path,string wspname)
        {
            Guid solutionID = new Guid();

            try
            {
                XmlDocument xdoc = new XmlDocument();

                if (!cbManifest.Checked)
                {
                    // load manifest.xml it into the main xml doc
                    xdoc.Load(path + "\\" + txtmaifest.Text);
                }
                else
                {
                    // load manifest.xml it into the main xml doc
                    xdoc.Load(path + "\\" + wspname);
                }

                try
                {
                    //extract id
                    solutionID = new Guid(xdoc.DocumentElement.Attributes["SolutionId"].Value);
                }
                catch
                {
                    throw new Exception("Unable to get Solution-Id from manifest.xml");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to get solution-id from manifest: " + ex.Message);
            }

            return solutionID;
        }

        /// <summary>
        /// upgrade wsp
        /// </summary>
        /// <param name="solutionFile"></param>
        /// <param name="ID"></param>
        public void UpgradeSolution(string solutionFile, Guid ID)
        {
            try
            {
                SPSolution solution = SPFarm.Local.Solutions[ID];
                solution.Upgrade(solutionFile, DateTime.Now);
            }
            catch (Exception ax)
            {
                MessageBox.Show("Unable to upgrade solution.", ax.Message);
            }
        }

        private void cbManifest_CheckedChanged(object sender, EventArgs e)
        {
            if (cbManifest.Checked == true)
            {
                txtmaifest.Enabled = false;
            }
            else
            {
                txtmaifest.Enabled = true;
            }
        }

        private void rbwsp_CheckedChanged(object sender, EventArgs e)
        {
            if (rbwsp.Checked == true)
            {
                searchtext = "*.wsp";
            }
        }

        private void rbcab_CheckedChanged(object sender, EventArgs e)
        {
            if (rbcab.Checked == true)
            {
                searchtext = "*.cab";
            }
        }

        private void frm1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.ManifestName = this.txtmaifest.Text;
            Properties.Settings.Default.WSPName = this.cbManifest.Checked;
            if (rbwsp.Checked == true)
            {
                Properties.Settings.Default.SearchFor = this.rbwsp.Checked;
            }
            else
            {
                Properties.Settings.Default.SearchFor = this.rbcab.Checked;
            }
            Properties.Settings.Default.location = this.txtDefaultFolder.Text;
            Properties.Settings.Default.zone = this.cbbZone.SelectedIndex;
            Properties.Settings.Default.Save();
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            txtmaifest.Text = "manifest.xml";
            cbManifest.Checked = false;
            rbwsp.Checked = true;
            
            txtDefaultFolder.Text = "C:\\Inetpub\\wwwroot\\wss\\VirtualDirectories\\";
            Properties.Settings.Default.Save();

            this.cbburlzone.SelectedIndex = 0;
            this.cbbZone.SelectedIndex = 0;
        }
    }
}
